package cn.touna.jss.common.mock;

import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Method;

/**
 * Mock注解日志类，实现记录监控日志
 */
//@Component
//@Aspect
public class MockAspect {
    private static final Logger logger = LogManager.getLogger(MockAspect.class);

    @Resource
    private TemplateUtil templateUtil;

    @Around("execution(* *(..)) && @annotation(mock)")
    public Object audit(ProceedingJoinPoint pjp, Mock mock) throws Throwable {
        Object result;
        try {
            if (false) {
                String mockSwitch = mock.mockSwitch();
                //DictionaryEntity dictionary = DictionaryCache.getDictionary(mockSwitch);
                //dictionary != null && JssConstant.Y.equalsIgnoreCase(dictionary.getValue())
                if (false) { // mock 开关为开
                    Class mockClass = mock.mockClass(); // 获取mock处理类
                    String mockMethodName = getMockMethodName(pjp, mock); //获取mock处理方法
                    Object[] args = pjp.getArgs() != null ? pjp.getArgs() : new Object[0]; // 获取传入参数列表
                    Object mockInvokeObj = mockClass.newInstance(); //获取mock处理类实例
                    String dynamicVariableValue = getDynamicVariableValue(mockMethodName, args, mockInvokeObj); //获取动态匹配模版值
                    Object[] mockArgs = getMockArgs(args, mockSwitch, dynamicVariableValue); //获取调用mock方法参数

                    Method mockMethod = getMockMethod(mockClass, mockMethodName, args, mockArgs); // 获取mock处理方法实例
                    result = mockMethod.invoke(mockInvokeObj, mockArgs); // 处理模版
                } else { // mock 开关为关 则 调用实际处理方法
                    result = pjp.proceed();
                }
            } else {
                result = pjp.proceed();
            }
            return result;
        } catch (Throwable throwable) {
            throw throwable;
        }
    }

    private Method getMockMethod(Class mockClass, String mockMethodName, Object[] args, Object[] mockArgs) throws NoSuchMethodException {
        Class<?>[] parameterTypes = new Class<?>[args.length + 1]; //mock 方法的入参类型
        for (int i = 0; i < mockArgs.length; i++) {
            parameterTypes[i] = mockArgs[i].getClass();
        }
        return mockClass.getMethod(mockMethodName, parameterTypes); //根据方法名加参数类型匹配mock类的方法
    }

    private Object[] getMockArgs(Object[] args, String mockSwitch, String dynamicVariableValue) throws IOException {
        Object[] mockArgs = new Object[args.length + 1];
        for (int i = 0; i < args.length; i++) {
            mockArgs[i] = args[i];
        }
        // 根据mock开关key+ 一个动态参数值  获取模版
        Template templateStr = templateUtil.getTemplate(mockSwitch, dynamicVariableValue);
        mockArgs[args.length] = templateStr; //模版

        return mockArgs;
    }

    private String getDynamicVariableValue(String mockMethodName, Object[] args, Object mockInvokeObj) {
        String dynamicVariableValue = null;
        if (mockInvokeObj instanceof MockIntf) {
            MockIntf mockIntfObj = (MockIntf) mockInvokeObj;
            // 根据方法名称和原始入参获取动态参数
            dynamicVariableValue = mockIntfObj.getDynamicVariableValue(mockMethodName, args);
        }
        return dynamicVariableValue;
    }

    private String getMockMethodName(ProceedingJoinPoint pjp, Mock mock) {
        String mockMethodName;
        String thisMethodName = pjp.getSignature().getName(); //获取当前执行的方法
        if (StringUtils.isEmpty(mock.mockMethod())) { // 如果未指定mock方法 则  指定方法名为 当前执行方法名
            mockMethodName = thisMethodName;
        } else {
            mockMethodName = mock.mockMethod();
        }
        return mockMethodName;
    }


}
